package com.wing.oauth2.controller.admin;

import cn.hutool.json.JSONObject;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.pig4cloud.captcha.GifCaptcha;
import com.wing.common.constant.SecurityConstants;
import com.wing.common.utils.JsonResult;
import com.wing.common.utils.Result;
import com.wing.redis.utils.redis.RedisHelper;
import com.wing.user.feign.UserClient;
import com.wing.web.utils.JwtUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.bind.annotation.*;

import java.security.KeyPair;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Api(value = "认证中心")
@RestController("oauth2Controller")
@RequestMapping("/oauth2/admin/user")
@AllArgsConstructor
@Slf4j
public class OAuth2Controller {

    private TokenEndpoint tokenEndpoint;
    private RedisHelper redisHelper;
    private KeyPair keyPair;
    private UserClient userClient;


    // @ApiOperation(value = "OAuth2认证", notes = "登录入口")
    // @ApiImplicitParams({
    //         @ApiImplicitParam(name = "grant_type", defaultValue = "password", value = "授权模式", required = true),
    //         @ApiImplicitParam(name = "client_id", defaultValue = "client", value = "Oauth2客户端ID", required = true),
    //         @ApiImplicitParam(name = "client_secret", defaultValue = "123456", value = "Oauth2客户端秘钥", required = true),
    //         @ApiImplicitParam(name = "refresh_token", value = "刷新token"),
    //         @ApiImplicitParam(name = "username", defaultValue = "admin", value = "用户名"),
    //         @ApiImplicitParam(name = "password", defaultValue = "123456", value = "用户密码")
    // })
    // @PostMapping("/login")
    // public Object postAccessToken(
    //         @ApiIgnore Principal principal,
    //         @ApiIgnore @RequestParam Map<String, String> parameters
    // ) throws HttpRequestMethodNotSupportedException {
    //
    //     /**
    //      * 获取登录认证的客户端ID
    //      *
    //      * 兼容两种方式获取Oauth2客户端信息（client_id、client_secret）
    //      * 方式一：client_id、client_secret放在请求路径中(注：当前版本已废弃)
    //      * 方式二：放在请求头（Request Headers）中的Authorization字段，且经过加密，例如 Basic Y2xpZW50OnNlY3JldA== 明文等于 client:secret
    //      */
    //     String clientId = RequestUtils.getOAuth2ClientId();
    //     log.info("OAuth认证授权 客户端ID:{}，请求参数：{}", clientId, JSONUtil.toJsonStr(parameters));
    //
    //     /**
    //      * knife4j接口文档测试使用
    //      *
    //      * 请求头自动填充，token必须原生返回，不能有任何包装，否则显示 undefined undefined
    //      * 账号/密码:  client_id/client_secret : client/123456
    //      */
    //     if (SecurityConstants.TEST_CLIENT_ID.equals(clientId)) {
    //         return tokenEndpoint.postAccessToken(principal, parameters).getBody();
    //     }
    //
    //     OAuth2AccessToken accessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
    //     return JsonResult.success(accessToken);
    // }

    @ApiOperation(value = "获取验证码")
    @GetMapping(value = "/getCaptcha")
    public JsonResult getCaptcha() {

        // 使用gif验证码
        GifCaptcha gifCaptcha = new GifCaptcha(130,48,4);

        // 存入redis并设置过期时间为30分钟
        String verCode = gifCaptcha.text().toLowerCase();
        String key = UUID.randomUUID().toString();
        String captchaKey = "captcha:" + key;
        redisHelper.valuePut(captchaKey, verCode);
        redisHelper.expire(captchaKey, 15, TimeUnit.MINUTES);

        // 将key和base64返回给前端
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("captchaKey", key);
        jsonObject.put("captchaImage", gifCaptcha.toBase64());

        return JsonResult.success(jsonObject);
    }

    @ApiOperation(value = "注销")
    @DeleteMapping("/logout")
    public JsonResult logout() {
        JSONObject payload = JwtUtils.getJwtPayload();
        // JWT唯一标识
        String jti = payload.getStr(SecurityConstants.JWT_JTI);
        // JWT过期时间戳(单位：秒)
        Long expireTime = payload.getLong(SecurityConstants.JWT_EXP);
        if (expireTime != null) {
            // 当前时间（单位：秒）
            long currentTime = System.currentTimeMillis() / 1000;
            if (expireTime > currentTime) {
                // token未过期，添加至缓存作为黑名单限制访问，缓存时间为token过期剩余时间
                redisHelper.valuePut(SecurityConstants.TOKEN_BLACKLIST_PREFIX + jti, null, (expireTime - currentTime), TimeUnit.SECONDS);
            }
        } else {
            // token 永不过期则永久加入黑名单
            redisHelper.valuePut(SecurityConstants.TOKEN_BLACKLIST_PREFIX + jti, null);
        }
        return JsonResult.success("注销成功");
    }

    @ApiOperation(value = "修改用户状态", notes = "修改状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户id", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = "status", value = "状态：0正常，1冻结", required = true, dataType = "Integer", paramType = "form")
    })
    @PutMapping("/updateStatus")
    public JsonResult updateState(Long userId, Integer status) {
        if (status == null || (status != 0 && status != 1)) {
            return JsonResult.fail("status值需要在[0,1]中");
        }
        JsonResult result = userClient.updateStatus(userId, status);
        if (Result.isSuccess(result)) {
            if(status == 0){
                //禁用，用户ID加入禁用名单
                redisHelper.valuePut(SecurityConstants.TOKEN_DISABLEDLIST_PREFIX + userId, null);
            }else if(status == 1){
                //启用，删除禁用名单中用户ID
                redisHelper.remove(SecurityConstants.TOKEN_DISABLEDLIST_PREFIX + userId);
            }
            return JsonResult.success();
        }
        return JsonResult.fail();
    }

    @ApiOperation(value = "获取公钥")
    @GetMapping("/public-key")
    public Map<String, Object> getPublicKey() {
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAKey key = new RSAKey.Builder(publicKey).build();
        return new JWKSet(key).toJSONObject();
    }
}
